package cz.stv.pecinovsky.město;

import cz.stv.pecinovsky.správceplátna.IPosuvný;
import cz.stv.pecinovsky.správceplátna.Přesouvač;
import cz.stv.pecinovsky.správceplátna.SprávcePlátna;
import cz.stv.pecinovsky.správceplátna.Multipřesouvač;

import cz.stv.pecinovsky.utility.IO;
import cz.stv.pecinovsky.utility.Pozice;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


/*******************************************************************************
 * Knihovní třída {@code TestUtility} obsahuje sbírku pomocných metod
 * používaných testovacími třídami objektů implementujících rozhraní
 * {@link IModulový}.
 *
 * @author  Rudolf PECINOVSKÝ
 * @version 1.10.2678 — 2011-10-27
 */
public class TestUtility extends junit.framework.TestCase
{
//== KONSTANTNÍ ATRIBUTY TŘÍDY =================================================

    private static final SprávcePlátna SP = SprávcePlátna.getInstance();



//== PROMĚNNÉ ATRIBUTY TŘÍDY ===================================================

    /** Pozice, na níž se bude přesouvat objekt testovaný v metodě
     *  {@link #poziceVelikost(IModulový)}. */
    private static Pozice pozice;

    /** Velikost menšího z modulů, které se budou nastavovat objektu
     *  testovanému v metodě {@link #poziceVelikost(IModulový)}. */
    private static int malýModul;

    /** Velikost většího z modulů, které se budou nastavovat objektu
     *  testovanému v metodě {@link #poziceVelikost(IModulový)}. */
    private static int velkýModul;



//== STATICKÝ INICIALIZAČNÍ BLOK - STATICKÝ KONSTRUKTOR ========================
//== KONSTANTNÍ ATRIBUTY INSTANCÍ ==============================================
//== PROMĚNNÉ ATRIBUTY INSTANCÍ ================================================
//== PŘÍSTUPOVÉ METODY VLASTNOSTÍ TŘÍDY ========================================

    /***************************************************************************
     * Vyzkouší změny pozice a velikosti zadaného objektu;
     * parametry testu je třeba předem nastavit pomocí metody
     *
     * @param pozice    Pozice, na kterou se testovaný objekt přesune
     * @param malý      Malá velikost modulu, jež se testovanému objektu zadá
     * @param velký     Velká velikost modulu, jež se testovanému objektu zadá
     */
    public static void setPoziceModuly(Pozice pozice, int malý, int velký)
    {
        TestUtility.pozice = pozice;
        malýModul  = malý;
        velkýModul = velký;
    }



//== OSTATNÍ NESOUKROMÉ METODY TŘÍDY ===========================================

    /***************************************************************************
     * Vyčistí plátno, postaví malý okruh a objede jej zadaným otočným objektem.
     * Zakomentovaný příkaz umožňuje postavit a objíždět okruh kolem plátna.
     *
     * @param objekt Testovaný otočný objekt
     */
    public static void objeďOkruh(IOtočný objekt)
    {
        SP.odstraňVše();
        int k = SP.getKrok();
//        Okruh  okruh  = Okruh.elko(new Pozice(k,k));
        Okruh  okruh  = Okruh.čtverec(new Pozice(k,k));
        Otočný otočný = new Otočný(objekt);
        otočný.objížděj(okruh);


        IO.zpráva("Až se pokocháš, stiskni OK");
        Multipřesouvač.getInstance().zastavVše();
    }


    /***************************************************************************
     * Vyzkouší změny pozice a velikosti zadaného objektu;
     * parametry testu je třeba předem nastavit pomocí metody
     *
     * @param objekt Testovaný objekt
     */
    public static void poziceVelikost(IModulový objekt)
    {
        poziceVelikost(objekt, pozice, malýModul, velkýModul);
    }


    /***************************************************************************
     * Vyzkouší změny pozice a velikosti zadaného objektu s použitím
     * zadaných parametrů.
     *
     * @param objekt    Testovaný objekt
     * @param pozice    Pozice, na kterou se testovaný objekt přesune
     * @param malý      Malá velikost modulu, jež se testovanému objektu zadá
     * @param velký     Velká velikost modulu, jež se testovanému objektu zadá
     */
    public static void poziceVelikost(IModulový objekt,
                                      Pozice pozice, int malý, int velký)
    {
        final int ms = 500;
        objekt.setPozice(pozice.x, pozice.y);
        IO.čekej(ms);
        objekt.setModul(velký);
        IO.čekej(ms);
        objekt.setModul(malý);
        IO.čekej(ms);
        SP.odstraň(objekt);
        IO.čekej(ms);
    }


    /***************************************************************************
     * Prohodí pozice zadaných objektů a nechá zkontrolovat,
     * zda si objekty své pozice doopravdy vyměnily.
     *
     * @param o1 První objekt
     * @param o2 Druhý objekt
     */
    public static void prohoďPoziceSKontrolou(IPosuvný o1, IPosuvný o2)
    {
        Přesouvač přesouvač = new Přesouvač(10);
        Pozice p1 = o1.getPozice();
        Pozice p2 = o2.getPozice();

        System.out.println("Výchozí: " + p1 + " <--> " + p2);

        přesouvač.přesunNa(p2, o1);
        přesouvač.přesunNa(p1, o2);

        System.out.println("Cílová:  " + o1.getPozice() +
                              " <--> " + o2.getPozice() + "\n");

        assertEquals(p1, o2.getPozice());
        assertEquals(p2, o1.getPozice());
    }


    /***************************************************************************
     * Seřadí objekty v seznamu podle velikosti modulu,
     * stejně velké objekty pak seřadí nejprve podle vodorovné souřadnice
     * a když mají i tu stejnou, tak podle svislé souřadnice;
     * výsledný seznam vytiskne na standardní výstup.
     *
     * @param seznam Seznam s řazenými objekty
     */
    public static void seřaďSeznam(List<IModulový> seznam)
    {
        Collections.sort(seznam, new CompModulXY());
        System.out.println("\nModulově a pozičně seřazené instance:");
        int i = 0;
        for (IModulový im : seznam) {
            System.out.println(++i + ".  " + im);
        }
    }


    /***************************************************************************
     * Vytvoří nový seznam jako instanci třídy {@link ArrayList}
     * a naplní jej hodnotami zadanými jako parametry.
     *
     * @param pole  Hodnoty, jimiž bude vytvořený seznam inicializován
     * @return Nový seznam naplněný zadanými hodnotami
     */
    public static List<IModulový> newListIModulový(IModulový... pole)
    {
        List<IModulový> seznam = new ArrayList<IModulový>();
        for (IModulový im : pole) {
            seznam.add(im);
        }
        return seznam;
    }



//##############################################################################
//== KONSTRUKTORY A TOVÁRNÍ METODY =============================================

    /** Soukromý konstruktor brání vytvoření instancí. */
    private TestUtility( String název ) {}

//== PŘÍPRAVA A ÚKLID PŘÍPRAVKU ================================================
//== SOUKROMÉ A POMOCNÉ METODY TŘÍDY ===========================================
//== SOUKROMÉ A POMOCNÉ METODY INSTANCÍ ========================================
//== INTERNÍ DATOVÉ TYPY =======================================================

    private static class CompModulXY implements Comparator<IModulový>
    {
        /***********************************************************************
         * Porovná objekty podle velikosti jejich modulu, stejně velké objekty
         * pak nejprve podle vodorovné souřadnice (menší souřadnice dopředu)
         * a když mají i tu stejnou, tak podle svislé souřadnice
         * (opět menší souřadnice dopředu).
         *
         * @param o1  První z porovnávaných objektů
         * @param o2  Druhý z porovnávaných objektů
         * @return Výsledek porovnání
         */
        @Override
        public int compare(IModulový o1, IModulový o2)
        {
            //Má-li být o1 < o2, musí se vrátit záporné číslo
            //Větší má být před menším =>  (o1 < o2) <=> ((o2-o1) < 0)
            if (o1.getModul() != o2.getModul()) {
                return o2.getModul() - o1.getModul();
            } else {
                //U souřadnic se dopředu probojuje naopak ten menší, takže
                //Menší má být před větším =>  (o1 < o2) <=> ((o1-o2) < 0)
                Pozice p1 = o1.getPozice();
                Pozice p2 = o2.getPozice();
                if (p2.x != p1.x) {
                    return p1.x - p2.x;
                } else {
                    return p1.y - p2.y;
                }
            }
        }
    }



//== VLASTNÍ TESTY =============================================================
//
//     /***************************************************************************
//      *
//      */
//     public void testXXX()
//     {
//     }
}

